1
2
3
4 package joeq.Scheduler;
5
6 import java.util.Iterator;
7 import java.util.Random;
8 import joeq.Allocator.CodeAllocator;
9 import joeq.Allocator.HeapAllocator;
10 import joeq.Allocator.RuntimeCodeAllocator;
11 import joeq.Allocator.SimpleAllocator;
12 import joeq.Class.PrimordialClassLoader;
13 import joeq.Class.jq_Class;
14 import joeq.Class.jq_DontAlign;
15 import joeq.Class.jq_InstanceMethod;
16 import joeq.Class.jq_StaticField;
17 import joeq.Class.jq_StaticMethod;
18 import joeq.Main.jq;
19 import joeq.Memory.CodeAddress;
20 import joeq.Memory.HeapAddress;
21 import joeq.Memory.StackAddress;
22 import joeq.Runtime.Debug;
23 import joeq.Runtime.StackCodeWalker;
24 import joeq.Runtime.SystemInterface;
25 import joeq.Runtime.Unsafe;
26 import jwutil.strings.Strings;
27 import jwutil.util.Assert;
28
29 /***
30 * A jq_NativeThread corresponds to a virtual CPU in the scheduler. There is one
31 * jq_NativeThread object for each underlying (heavyweight) kernel thread.
32 * The Java (lightweight) threads are multiplexed across the jq_NativeThreads.
33 *
34 * @author John Whaley <jwhaley@alum.mit.edu>
35 * @author Miho Kurano
36 * @version $Id: jq_NativeThread.java 1941 2004-09-30 03:37:06Z joewhaley $
37 */
38 public class jq_NativeThread implements jq_DontAlign {
39
40 /*** Trace flag. When this is true, prints out debugging information about
41 * what is going on in the scheduler.
42 */
43 public static
44 public static
45
46 public static final boolean STATISTICS = true;
47
48 /*** Data structure to represent the native thread that exists at virtual
49 * machine startup.
50 */
51 public static final jq_NativeThread initial_native_thread = new jq_NativeThread(0);
52
53 /***
54 * Initialize the initial native thread.
55 * Must be the first thing called at virtual machine startup.
56 */
57 public static void initInitialNativeThread() {
58 initial_native_thread.pid = SystemInterface.init_thread();
59 Unsafe.setThreadBlock(initial_native_thread.schedulerThread);
60 initial_native_thread.thread_handle = SystemInterface.get_current_thread_handle();
61 initial_native_thread.myHeapAllocator.init();
62 initial_native_thread.myCodeAllocator.init();
63 if (TRACE) SystemInterface.debugwriteln("Initial native thread initialized");
64 }
65
66 /*** An array of all native threads. */
67 public static jq_NativeThread[] native_threads;
68
69 /*** Number of Java threads that are currently active.
70 * When this equals the number of active daemon threads, it is time to shut down.
71 */
72 private static volatile int num_of_java_threads = 0;
73 /*** Number of daemon threads that are currently active.
74 * Daemon threads do not keep the VM running.
75 */
76 private static volatile int num_of_daemon_threads = 0;
77
78 /*** Handle for this native thread. */
79 /*** NOTE: C code relies on this field being first. */
80 private int thread_handle;
81
82 /*** Pointer to the Java thread that is currently executing on this native thread. */
83 /*** NOTE: C code relies on this field being second. */
84 private jq_Thread currentThread;
85
86 /*** Process ID for this native thread. */
87 /*** NOTE: C code relies on this field being third. */
88 private int pid;
89
90 /*** counter for preempted thread */
91 private int preempted_thread_counter;
92
93 /*** Queue of ready Java threads. */
94 private final jq_ThreadQueue[] readyQueue;
95 /*** Queue of idle Java threads. */
96 private final jq_ThreadQueue idleQueue;
97 /*** Queue of Java threads transferred from another native thread. */
98 private final jq_SynchThreadQueue transferQueue;
99
100 /*** Thread-local allocators. */
101 private CodeAllocator myCodeAllocator;
102 private HeapAllocator myHeapAllocator;
103
104 /*** Original thread's stack pointer and base pointer.
105 * These are used for longjmp'ing back to schedulerLoop when the currently
106 * executing Java thread exits.
107 */
108 StackAddress original_esp, original_ebp;
109
110 /*** The index of this native thread. */
111 private final int index;
112
113 /*** The Java thread that is executing while we are in the scheduler. */
114 private final jq_Thread schedulerThread;
115
116 public static final int MAX_NATIVE_THREADS = 16;
117
118 private static boolean all_native_threads_initialized;
119 private static boolean all_native_threads_started;
120
121 /*** Initialize the extra native threads.
122 *
123 * @param nt initial native thread
124 * @param num number of native threads to initialize
125 */
126 public static void initNativeThreads(jq_NativeThread nt, int num) {
127 Assert._assert(num <= MAX_NATIVE_THREADS);
128 native_threads = new jq_NativeThread[num];
129 native_threads[0] = nt;
130 for (int i = 1; i < num; ++i) {
131 jq_NativeThread nt2 = native_threads[i] = new jq_NativeThread(i);
132 nt2.thread_handle = SystemInterface.create_thread(_nativeThreadEntry.getDefaultCompiledVersion().getEntrypoint(), HeapAddress.addressOf(nt2));
133 nt2.myHeapAllocator.init();
134 nt2.myCodeAllocator.init();
135 if (TRACE) SystemInterface.debugwriteln("Native thread " + i + " initialized");
136 }
137 all_native_threads_initialized = true;
138 }
139
140 /*** Start up the extra native threads.
141 */
142 public static void startNativeThreads() {
143 for (int i = 1; i < native_threads.length; ++i) {
144 if (TRACE) SystemInterface.debugwriteln("Native thread " + i + " started");
145 native_threads[i].resume();
146 }
147 all_native_threads_started = true;
148 }
149
150 /*** Returns true iff all native threads are initialized. */
151 public static boolean allNativeThreadsInitialized() {
152 return all_native_threads_initialized;
153 }
154
155 /*** Returns the jq_Thread that is currently running on this native thread. */
156 public jq_Thread getCurrentThread() {
157 return currentThread;
158 }
159
160 /*** Get the native thread-local code allocator. */
161 public CodeAllocator getCodeAllocator() {
162 return myCodeAllocator;
163 }
164
165 /*** Get the native thread-local heap allocator. */
166 public HeapAllocator getHeapAllocator() {
167 return myHeapAllocator;
168 }
169
170 /*** Get the currently-executing Java thread. */
171 public jq_Thread getCurrentJavaThread() {
172 return currentThread;
173 }
174
175 public static final int NUM_OF_QUEUES = 10;
176
177 /*** Create a new jq_NativeThread (only called from initNativeThreads(),
178 * and during bootstrap initialization of initial_native_thread and
179 * break_nthread field) */
180 private jq_NativeThread(int i) {
181 readyQueue = new jq_ThreadQueue[NUM_OF_QUEUES];
182 for (int k = 0; k < NUM_OF_QUEUES; ++k) {
183 readyQueue[k] = new jq_ThreadQueue();
184 }
185 idleQueue = new jq_ThreadQueue();
186 transferQueue = new jq_SynchThreadQueue();
187 myHeapAllocator = new SimpleAllocator();
188 myCodeAllocator = new RuntimeCodeAllocator();
189 index = i;
190 preempted_thread_counter = 0;
191 Thread t = new Thread("_scheduler_" + i);
192 currentThread = schedulerThread = ThreadUtils.getJQThread(t);
193 if (schedulerThread != null) {
194 schedulerThread.disableThreadSwitch();
195 schedulerThread.setNativeThread(this);
196 schedulerThread.isScheduler = true;
197 } else {
198
199 Assert._assert(!jq.IsBootstrapping && !jq.RunningNative);
200 }
201 }
202
203 /*** Create a new jq_NativeThread that is tied to a specific jq_Thread. */
204 jq_NativeThread(jq_Thread t) {
205 readyQueue = null;
206 idleQueue = null;
207 transferQueue = null;
208 myHeapAllocator = new SimpleAllocator();
209 myCodeAllocator = new RuntimeCodeAllocator();
210 index = -1;
211 currentThread = schedulerThread = t;
212 t.setNativeThread(this);
213 t.isScheduler = true;
214 }
215
216 /*** Starts up/resumes this native thread. */
217 public void resume() {
218 SystemInterface.resume_thread(thread_handle);
219 }
220
221 /*** Suspends this native thread. */
222 public void suspend() {
223 SystemInterface.suspend_thread(thread_handle);
224 }
225
226 /*** Gets context of this native thread and puts it in r. */
227 public boolean getContext(jq_RegisterState r) {
228 return SystemInterface.get_thread_context(pid, r);
229 }
230
231 /*** Sets context of this native thread to r. */
232 public boolean setContext(jq_RegisterState r) {
233 return SystemInterface.set_thread_context(pid, r);
234 }
235
236 int chosenAsLeastBusy;
237
238 /*** Returns the least-busy native thread. */
239 static jq_NativeThread getLeastBusyThread() {
240 int min_i = 0;
241 int min = native_threads[min_i].preempted_thread_counter +
242 native_threads[min_i].transferQueue.length();
243 for (int i = 1; i < native_threads.length; ++i) {
244 int v = native_threads[i].preempted_thread_counter +
245 native_threads[i].transferQueue.length();
246 if (v < min) {
247 min = v;
248 min_i = i;
249 }
250 }
251 if (STATISTICS)
252 native_threads[min_i].chosenAsLeastBusy++;
253 return native_threads[min_i];
254 }
255
256 /*** Put the given Java thread on the queue of the least-busy native thread. */
257 public static void startJavaThread(jq_Thread t) {
258
259 _num_of_java_threads.getAddress().atomicAdd(1);
260 if (t.isDaemon())
261 _num_of_daemon_threads.getAddress().atomicAdd(1);
262
263
264 jq_NativeThread nt = getLeastBusyThread();
265
266 Assert._assert(t.isThreadSwitchEnabled());
267 t.disableThreadSwitch();
268
269 CodeAddress ip = t.getRegisterState().getEip();
270 if (TRACE) SystemInterface.debugwriteln("Java thread " + t + " enqueued on native thread " + nt + " ip: " + ip.stringRep() + " cc: " + CodeAllocator.getCodeContaining(ip));
271
272
273
274 jq_Thread my_t = Unsafe.getThreadBlock();
275 my_t.disableThreadSwitch();
276 jq_NativeThread my_nt = my_t.getNativeThread();
277 Unsafe.setThreadBlock(my_nt.schedulerThread);
278
279 nt.transferQueue.enqueue(t);
280
281 Unsafe.setThreadBlock(my_t);
282 my_t.enableThreadSwitch();
283 }
284
285 /*** End the currently-executing Java thread and go back to the scheduler loop
286 * to pick up another thread.
287 */
288 public static void endCurrentJavaThread() {
289 jq_Thread t = Unsafe.getThreadBlock();
290 if (TRACE) Debug.writeln("Ending Java thread " + t);
291 Assert._assert(!t.isThreadSwitchEnabled());
292 _num_of_java_threads.getAddress().atomicSub(1);
293 if (TRACE) Debug.writeln("Number of Java threads now: " + num_of_java_threads);
294 if (t.isDaemon())
295 _num_of_daemon_threads.getAddress().atomicSub(1);
296 jq_NativeThread nt = t.getNativeThread();
297 Unsafe.setThreadBlock(nt.schedulerThread);
298 nt.currentThread = nt.schedulerThread;
299
300 CodeAddress ip = _schedulerLoop.getDefaultCompiledVersion().getEntrypoint();
301 StackAddress fp = nt.original_ebp;
302 StackAddress sp = nt.original_esp;
303 if (TRACE) SystemInterface.debugwriteln("Long jumping back to schedulerLoop, ip:" + ip.stringRep() + " fp: " + fp.stringRep() + " sp: " + sp.stringRep());
304 HeapAddress a = (HeapAddress)sp.offset(4).peek();
305 Assert._assert(a.asObject() == nt, "arg to schedulerLoop got corrupted: " + a.stringRep() + " should be " + HeapAddress.addressOf(nt).stringRep());
306 Unsafe.longJump(ip, fp, sp, 0);
307 Assert.UNREACHABLE();
308 }
309
310 public static boolean USE_INTERRUPTER_THREAD = false;
311
312 public jq_InterrupterThread it;
313
314 /*** The entry point for new native threads.
315 */
316 public void nativeThreadEntry() {
317 if (this != initial_native_thread)
318 this.pid = SystemInterface.init_thread();
319 Unsafe.setThreadBlock(this.schedulerThread);
320 Assert._assert(this.currentThread == this.schedulerThread);
321
322 if (USE_INTERRUPTER_THREAD) {
323
324 it = new jq_InterrupterThread(this);
325 } else {
326
327 SystemInterface.set_interval_timer(SystemInterface.ITIMER_VIRTUAL, 10);
328 }
329
330
331 StackAddress sp = StackAddress.getStackPointer();
332 StackAddress fp = StackAddress.getBasePointer();
333
334 this.original_esp = (StackAddress) sp.offset(-CodeAddress.size()-HeapAddress.size());
335 this.original_ebp = fp;
336
337 if (TRACE) SystemInterface.debugwriteln("Started native thread: " + this + " sp: " + this.original_esp.stringRep() + " fp: " + this.original_ebp.stringRep());
338
339
340 this.schedulerLoop();
341 Assert.UNREACHABLE();
342 }
343
344 public void schedulerLoop() {
345 HeapAddress a = (HeapAddress) this.original_esp.offset(4).peek();
346 Assert._assert(a.asObject() == this);
347
348
349
350 Assert._assert(Unsafe.getThreadBlock() == this.schedulerThread);
351 for (;;) {
352
353 if (this == initial_native_thread &&
354 num_of_daemon_threads == num_of_java_threads)
355 break;
356 Assert._assert(currentThread == schedulerThread);
357
358 jq_Thread t = getNextReadyThread();
359 if (t == null) {
360
361 if (TRACE) SystemInterface.debugwriteln("Native thread " + this + " is idle!");
362 SystemInterface.yield();
363 } else {
364 Assert._assert(!t.isThreadSwitchEnabled());
365 if (TRACE) SystemInterface.debugwriteln("Native thread " + this + " scheduler loop: switching to Java thread " + t);
366 currentThread = t;
367 SystemInterface.set_current_context(t, t.getRegisterState());
368 Assert.UNREACHABLE();
369 }
370 }
371 dumpStatistics();
372 SystemInterface.die(0);
373 Assert.UNREACHABLE();
374 }
375
376 public static void dumpStatistics() {
377 for (int i = 0; i < native_threads.length; ++i) {
378 native_threads[i].dumpStats();
379 }
380 }
381
382 public void dumpStats() {
383 if (STATISTICS) {
384 Debug.write("Native thread ");
385 Debug.write(index);
386 Debug.write(": transferred out=");
387 Debug.write(transferredOut);
388 Debug.write("(");
389 Debug.write(failedTransferOut);
390 Debug.write(" failed) in=");
391 Debug.writeln(transferredIn);
392 Debug.write(" : chosen as least busy=");
393 Debug.writeln(chosenAsLeastBusy);
394 for (int i = 0; i < readyQueueLength.length; ++i) {
395 Debug.write(" : average ready queue length ");
396 Debug.write(i);
397 Debug.write(": ");
398 System.out.println((double)readyQueueLength[i] / readyQueueN);
399 }
400 Debug.write(" : preempted thread length=");
401 System.out.println((double)preemptedThreadsLength / readyQueueN);
402 }
403 if (it != null && jq_InterrupterThread.STATISTICS) {
404 Debug.write("Native thread ");
405 Debug.write(index);
406 Debug.write(": ");
407 it.dumpStatistics();
408 }
409 }
410
411 /*** Thread switch based on a timer or poker interrupt. */
412 public void threadSwitch() {
413 jq_Thread t1 = this.currentThread;
414 t1.wasPreempted = true;
415 if (TRACE) SystemInterface.debugwriteln("Timer interrupt in native thread: " + this + " Java thread: " + t1);
416 switchThread();
417 Assert.UNREACHABLE();
418 }
419
420 /*** Thread switch based on explicit yield. */
421 public void yieldCurrentThread() {
422 jq_Thread t1 = this.currentThread;
423 if (t1 == this.schedulerThread) {
424
425
426
427
428
429 t1.enableThreadSwitch();
430 Assert._assert(!t1.isThreadSwitchEnabled());
431 return;
432 }
433 t1.wasPreempted = false;
434 if (TRACE) SystemInterface.debugwriteln("Explicit yield in native thread: " + this + " Java thread: " + t1);
435 switchThread();
436 Assert.UNREACHABLE();
437 }
438
439 private void switchThread() {
440
441 jq_Thread t1 = this.currentThread;
442 Unsafe.setThreadBlock(this.schedulerThread);
443 this.currentThread = this.schedulerThread;
444 CodeAddress ip = (CodeAddress) StackAddress.getBasePointer().offset(StackAddress.size()).peek();
445 if (TRACE) SystemInterface.debugwriteln("Thread switch in native thread: " + this + " Java thread: " + t1 + " ip: " + ip.stringRep() + " cc: " + CodeAllocator.getCodeContaining(ip));
446 if (t1.isThreadSwitchEnabled()) {
447 SystemInterface.debugwriteln("Java thread " + t1 + " has thread switching enabled on threadSwitch entry!");
448 SystemInterface.die(-1);
449 }
450 Assert._assert(t1 != this.schedulerThread);
451
452
453
454 jq_RegisterState state = t1.getRegisterState();
455 state.setEip((CodeAddress) state.getEsp().peek());
456 state.setEsp((StackAddress) state.getEsp().offset(StackAddress.size() + CodeAddress.size()));
457
458
459 jq_Thread t2 = getNextReadyThread();
460 transferExtraWork();
461 if (t2 == null) {
462
463 t2 = t1;
464 } else {
465 ip = t2.getRegisterState().getEip();
466 if (TRACE) SystemInterface.debugwriteln("New ready Java thread: " + t2 + " ip: " + ip.stringRep() + " cc: " + CodeAllocator.getCodeContaining(ip));
467 int priority = t1.getPriority();
468 readyQueue[priority].enqueue(t1);
469 if (t1.wasPreempted && !t1.isDaemon())
470 ++preempted_thread_counter;
471 Assert._assert(!t2.isThreadSwitchEnabled());
472 }
473 currentThread = t2;
474 SystemInterface.set_current_context(t2, t2.getRegisterState());
475 Assert.UNREACHABLE();
476 }
477
478 public void yieldCurrentThreadTo(jq_Thread t) {
479 jq_Thread t1 = this.currentThread;
480 if (t1 == this.schedulerThread) {
481
482
483
484
485
486 t1.enableThreadSwitch();
487 Assert._assert(!t1.isThreadSwitchEnabled());
488 return;
489 }
490 t1.wasPreempted = false;
491 switchThread(t);
492 Assert.UNREACHABLE();
493 }
494
495 /*** Performs a thread switch to a specific thread in our local queue. */
496 private void switchThread(jq_Thread t2) {
497
498 jq_Thread t1 = this.currentThread;
499
500 Unsafe.setThreadBlock(this.schedulerThread);
501 this.currentThread = this.schedulerThread;
502 CodeAddress ip = (CodeAddress) StackAddress.getBasePointer().offset(StackAddress.size()).peek();
503 if (TRACE) SystemInterface.debugwriteln("Thread switch in native thread: " + this + " Java thread: " + t1 + " ip: " + ip.stringRep() + " cc: " + CodeAllocator.getCodeContaining(ip));
504 if (t1.isThreadSwitchEnabled()) {
505 SystemInterface.debugwriteln("Java thread " + t1 + " has thread switching enabled on threadSwitch entry!");
506 SystemInterface.die(-1);
507 }
508 Assert._assert(t1 != this.schedulerThread);
509
510
511
512 jq_RegisterState state = t1.getRegisterState();
513 state.setEip((CodeAddress) state.getEsp().peek());
514 state.setEsp((StackAddress) state.getEsp().offset(StackAddress.size() + CodeAddress.size()));
515
516 if (t1 != t2) {
517
518 for (int i = 0; ; ++i) {
519 if (i == readyQueue.length) {
520
521 Assert.UNREACHABLE();
522 return;
523 }
524 boolean exists = readyQueue[i].remove(t2);
525 if (exists) break;
526 }
527 if (t2.wasPreempted && !t2.isDaemon())
528 --preempted_thread_counter;
529 }
530 transferExtraWork();
531 if (t1 != t2) {
532 ip = t2.getRegisterState().getEip();
533 if (TRACE) SystemInterface.debugwriteln("New ready Java thread: " + t2 + " ip: " + ip.stringRep() + " cc: " + CodeAllocator.getCodeContaining(ip));
534 int priority = t1.getPriority();
535 readyQueue[priority].enqueue(t1);
536 if (t1.wasPreempted && !t1.isDaemon())
537 ++preempted_thread_counter;
538 Assert._assert(!t2.isThreadSwitchEnabled());
539 }
540 currentThread = t2;
541 SystemInterface.set_current_context(t2, t2.getRegisterState());
542 Assert.UNREACHABLE();
543 }
544
545 public static float TRANSFER_THRESHOLD = 1.5f;
546
547 int transferredOut;
548 int failedTransferOut;
549 /*** Transfer extra work from our ready queue into a less-busy thread's transfer queue. */
550 private void transferExtraWork() {
551 jq_NativeThread that = getLeastBusyThread();
552 if (this == that) return;
553
554 if (this.preempted_thread_counter*TRANSFER_THRESHOLD > (that.preempted_thread_counter+1)) {
555
556 int i;
557 for (i = readyQueue.length-1; i >= 0; --i) {
558 if (this.readyQueue[i].length() > that.readyQueue[i].length()) {
559 if (STATISTICS) ++transferredOut;
560
561 jq_Thread t2 = this.readyQueue[i].dequeue();
562 Assert._assert(!t2.isThreadSwitchEnabled());
563 if (t2.wasPreempted && !t2.isDaemon())
564 --preempted_thread_counter;
565 that.transferQueue.enqueue(t2);
566 break;
567 }
568 }
569 if (STATISTICS && i < 0)
570 ++failedTransferOut;
571 }
572 }
573
574 public boolean DETERMINISTIC = false;
575
576 /***
577 * GCD of relatively_prime_value and the maximum value in
578 * DISTRIBUTION should be 1.
579 */
580 public static final int relatively_prime_value = 37;
581 public static final int[] DISTRIBUTION = {
582 5, 11, 18, 26, 35, 45, 56, 68, 81, 100
583 };
584 /***
585 * Keeps track of last value used, so we can compute the next value.
586 */
587 int distCounter;
588
589 Random rng = new Random();
590
591 private jq_ThreadQueue chooseNextQueue() {
592 if (DETERMINISTIC) {
593 distCounter += relatively_prime_value;
594 int max = DISTRIBUTION[DISTRIBUTION.length-1];
595 while (distCounter >= max) {
596 distCounter -= max;
597 }
598 } else {
599
600 int max = DISTRIBUTION[DISTRIBUTION.length-1];
601 distCounter = rng.nextInt(max);
602 }
603 for (int i = 0; ; ++i) {
604 if (distCounter < DISTRIBUTION[i]) {
605 if (!readyQueue[i].isEmpty()) return readyQueue[i];
606 int c;
607 if (DETERMINISTIC) {
608 c = ((distCounter&1)==1) ? 1 : -1;
609 } else {
610 c = rng.nextBoolean() ? 1 : -1;
611 }
612 for (int j = i + c; j < DISTRIBUTION.length && j >= 0; j += c) {
613 if (!readyQueue[j].isEmpty()) return readyQueue[j];
614 }
615 c = -c;
616 for (int j = i + c; j < DISTRIBUTION.length && j >= 0; j += c) {
617 if (!readyQueue[j].isEmpty()) return readyQueue[j];
618 }
619 return null;
620 }
621 }
622 }
623
624 int readyQueueLength[] = new int[10];
625 int preemptedThreadsLength;
626 int readyQueueN;
627 int transferredIn;
628 /*** Get the next ready thread from the transfer queue or the ready queue.
629 * Return null if there are no threads ready.
630 */
631 private jq_Thread getNextReadyThread() {
632 if (!transferQueue.isEmpty()) {
633 if (STATISTICS) transferredIn++;
634 jq_Thread t = transferQueue.dequeue();
635 t.setNativeThread(this);
636 Assert._assert(!t.isThreadSwitchEnabled());
637 return t;
638 }
639 if (STATISTICS) {
640 for (int i = 0; i<readyQueue.length; ++i) {
641 readyQueueLength[i] += readyQueue[i].length();
642 }
643 preemptedThreadsLength += this.preempted_thread_counter;
644 ++readyQueueN;
645 if (CHECK) verifyCount();
646 }
647 jq_ThreadQueue q = chooseNextQueue();
648 while (q != null && !q.isEmpty()) {
649 jq_Thread t = q.dequeue();
650 if (t.wasPreempted && !t.isDaemon())
651 --preempted_thread_counter;
652 if (!t.isAlive()) continue;
653 Assert._assert(t.getNativeThread() == this);
654 Assert._assert(!t.isThreadSwitchEnabled());
655 return t;
656 }
657 return null;
658 }
659
660 private void verifyCount() {
661 int total = 0;
662 for (int i = 0; i < readyQueue.length; ++i) {
663 for (Iterator j = readyQueue[i].threads(); j.hasNext(); ) {
664 jq_Thread t = (jq_Thread) j.next();
665 if (t.wasPreempted && !t.isDaemon())
666 ++total;
667 }
668 }
669 Assert._assert(total == preempted_thread_counter);
670 }
671
672 public String toString() {
673 return "NT " + index + ":" + thread_handle + "(" + Strings.hex(this) + ")";
674 }
675
676 public int getIndex() { return index; }
677
678 public static void ctrl_break_handler() {
679
680 Unsafe.setThreadBlock(break_jthread);
681 break_nthread.thread_handle = SystemInterface.get_current_thread_handle();
682 if (!has_break_occurred) {
683 break_nthread.myHeapAllocator.init();
684 break_nthread.myCodeAllocator.init();
685 has_break_occurred = true;
686 }
687 SystemInterface.debugwriteln("*** BREAK! ***");
688 for (int i = 0; i < native_threads.length; ++i) {
689 SystemInterface.suspend_thread(native_threads[i].thread_handle);
690 }
691
692 joeq.Debugger.OnlineDebugger.debuggerEntryPoint();
693 for (int i = 0; i < native_threads.length; ++i) {
694 SystemInterface.resume_thread(native_threads[i].thread_handle);
695 }
696 }
697
698 public static void dumpAllThreads() {
699 jq_RegisterState rs = jq_RegisterState.create();
700 rs.setContextFlags(jq_RegisterState.CONTEXT_CONTROL);
701 for (int i = 0; i < native_threads.length; ++i) {
702 SystemInterface.get_thread_context(native_threads[i].pid, rs);
703 native_threads[i].dump(rs);
704 }
705 }
706
707 private static boolean has_break_occurred = false;
708 private static jq_NativeThread break_nthread;
709 private static jq_Thread break_jthread;
710
711 public static void initBreakThread() {
712 break_nthread = new jq_NativeThread(-1);
713 Thread t = new Thread("_break_");
714 break_jthread = ThreadUtils.getJQThread(t);
715 break_jthread.disableThreadSwitch();
716 break_jthread.setNativeThread(break_nthread);
717 if (TRACE) SystemInterface.debugwriteln("Break thread initialized");
718 }
719
720
721
722 public static void suspendAllThreads() {
723 if (!all_native_threads_started) {
724 if (TRACE) Debug.writeln("Native threads haven't started yet.");
725 return;
726 }
727 if (TRACE) Debug.writeln("Suspending all native threads: ", native_threads.length);
728 jq_Thread t = Unsafe.getThreadBlock();
729 Assert._assert(!t.isThreadSwitchEnabled());
730 for (int i = 0; i < native_threads.length; ++i) {
731 jq_NativeThread nt = native_threads[i];
732 if (nt == t.getNativeThread()) continue;
733 for (;;) {
734 if (TRACE) Debug.writeln("Attempting to suspend native thread ", i);
735 nt.suspend();
736 jq_Thread t2 = nt.getCurrentJavaThread();
737 if (t2.isThreadSwitchEnabled()) break;
738 if (TRACE) Debug.writeln("Failed, trying again.");
739 nt.resume();
740 SystemInterface.msleep(0);
741 }
742 if (TRACE) Debug.writeln("Success!");
743 }
744 if (TRACE) Debug.writeln("Finished suspending native threads");
745 }
746
747 public static void resumeAllThreads() {
748 if (!all_native_threads_started) {
749 if (TRACE) Debug.writeln("Native threads haven't started yet.");
750 return;
751 }
752 if (TRACE) Debug.writeln("Resuming all native threads");
753 jq_Thread t = Unsafe.getThreadBlock();
754 Assert._assert(!t.isThreadSwitchEnabled());
755 for (int i = 0; i < native_threads.length; ++i) {
756 jq_NativeThread nt = native_threads[i];
757 if (nt == t.getNativeThread()) continue;
758 if (TRACE) Debug.writeln("Resuming native thread ", i);
759 nt.resume();
760 }
761 if (TRACE) Debug.writeln("All native threads resumed");
762 }
763
764 public void dump(jq_RegisterState regs) {
765 SystemInterface.debugwriteln(this + ": current Java thread = " + currentThread);
766 StackCodeWalker.stackDump(regs.getEip(), regs.getEbp());
767 for (int i = 0; i < readyQueue.length; ++i) {
768 SystemInterface.debugwriteln(this + ": ready queue "+i+" = " + readyQueue[i]);
769 }
770 SystemInterface.debugwriteln(this + ": idle queue = " + idleQueue);
771 SystemInterface.debugwriteln(this + ": transfer queue = " + transferQueue);
772 }
773
774 public jq_ThreadQueue getReadyQueue(int i) {
775 return this.readyQueue[i];
776 }
777 public jq_ThreadQueue getIdleQueue() {
778 return this.idleQueue;
779 }
780 public jq_ThreadQueue getTransferQueue() {
781 return this.transferQueue;
782 }
783
784 public static final jq_Class _class;
785 public static final jq_InstanceMethod _nativeThreadEntry;
786 public static final jq_InstanceMethod _schedulerLoop;
787 public static final jq_InstanceMethod _threadSwitch;
788 public static final jq_StaticMethod _ctrl_break_handler;
789 public static final jq_StaticField _num_of_java_threads;
790 public static final jq_StaticField _num_of_daemon_threads;
791
792 static {
793 _class = (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Scheduler/jq_NativeThread;");
794 _nativeThreadEntry = _class.getOrCreateInstanceMethod("nativeThreadEntry", "()V");
795 _schedulerLoop = _class.getOrCreateInstanceMethod("schedulerLoop", "()V");
796 _threadSwitch = _class.getOrCreateInstanceMethod("threadSwitch", "()V");
797 _ctrl_break_handler = _class.getOrCreateStaticMethod("ctrl_break_handler", "()V");
798 _num_of_java_threads = _class.getOrCreateStaticField("num_of_java_threads", "I");
799 _num_of_daemon_threads = _class.getOrCreateStaticField("num_of_daemon_threads", "I");
800 }
801 }